# ECS
Вся логика приложения в Bevy использует парадигму «Система Компонентов Сущностей» (_Entity Component System_, [ESC](https://en.wikipedia.org/wiki/Entity_component_system)). ECS — это шаблон программного обеспечения, который предполагает разбиение вашей программы на Сущности, Компоненты и Системы. Сущности это уникальные «вещи», которым присваиваются группы компоненты, которые затем обрабатываются с помощью систем.

К примеру, у одного объекта может быть компонент `Position`(позицию) и `Velocity`(скорость), в то время как у другого может быть компонент `Position` и `UI`(пользовательский интерфейс). Системы — это логика, которая работает на определённом наборе типов компонентов. У вас может быть система `movement`(перемещения), которая работает на всех объектах с компонентами `Position` и `Velocity`.

Шаблон ECS поощрает чистый, несвязанный дизайн, заставляя вас разбивать данные и логику вашего приложения на его основные компоненты. Это также помогает ускорить код за счёт оптимизапции шаблонов доступа к памяти и упрощения параллелизма.

# Bevy ECS
Это имплементация шаблона ECS в Bevy. В отличие от других реализаций ECS от Rust, которые часто требует сложных lifetimes(Rust-специфичный термин), traits, шаблонов построения или макросов, Bevy ECS использует обычные типы данных Rust для всех этих концепций:

* **Компоненты(Components)**: структуры Rust, реализующие признак(trait) `Component`
  ```rust
  #[derive(Component)]
  struct Position { x: f32, y: f32 }
  ```

* **Системы(Systems)**: обычные функции Rust
  ```rust
  fn print_position_system(query: Query<&Transform>) {
      for transform in &query {
          println!("position: {:?}", transform.translation);
      }
  }
  ```

* **Сущности(Entities)**: простой тип, содержащий уникальное целое число
  ```rust
  struct Entity(u64)
  ```

А сейчас давайте посмотрим, как это работает на практике!

# Ваша первая система
Скопируйте следующую функцию в файл `main.rs`:

```rust
fn hello_world() {
    println!("hello world!");
}
```

Это будет нашей первой системой. Оставшийся шаг — добавить его в наше приложение!

```rust
use bevy::app:App;

fn main() {
    App::new()
        .add_system(hello_world)
        .run();
}
```

Функция `add_system()` добавляет систему в расписание(`Shedule`) вашего приложения(`App`), но подробнее об этом будет позже.

Сейчас запустите ваше приложение используюя `cargo run`. Вы должны увидеть `hello world!` в вашем терминале.

# Ваш первый компонент
Приветствовать весь мир это отлично, но что если мы хотим поприветствовать определённого человека? В ECS вы обычно моделируете людей как сущности с набором компонентов, которые их определяют. Давайте начнем с обычного компонента `Person`.

Добавьте эту структуру в файл `main.rs`:

```rust
#[derive(Component)]
struct Person;
```

Но что если мы хотим, чтобы наши люди имели имена? В более традиционном дизайне мы могли бы просто привязать полке `name:String` к `Person`. Но другие сущности тоже могут иметь имена! К примеру, собаки также должны обладать именем. Часто имеет смысл разбивать типы данных на небольные фрагменты, чтобы стимулировать повторное использование кода. Итак, давайте создадим `Name` для нашего компонента:

```rust
#[derive(Component)]
struct Name(String);
```

Теперь мы можем добавлять `Людей` в наш `Мир` используя нашу «систему запуска». Системы запуска ничем не отличаются от обычных систем, но они запускаются ровно один раз, перед всеми другими системами, прямо при запуске нашего приложения. Давайте используем `Commands`, чтобы породить немного сущностей в наш `World`:

```rust
fn add_people(mut commands: Commands) {
    commands.spawn((Person, Name("Elaina Proctor".to_string())));
    commands.spawn((Person, Name("Renzo Hume".to_string())));
    commands.spawn((Person, Name("Zayna Nieves".to_string())));
}
```

Теперь регистрируем систему запуска так:

```rust
fn main() {
    App::new()
        .add_startup_system(add_people)
        .add_system(hello_world)
        .run();
}
```

Мы могли бы запусктить это приложение прямо сейчас, и сначала запустилась бы система `add_people`, а затем `hello_world`. Но наши новые люди сейчас ничего не делают! Давайте сделаем систему, которая должным образом приветствует новых граждан нашего `Мира`:

```rust
fn greet_people(query: Query<&Name, With<Person>>) {
    for name in &query {
        println!("hello {}!", name.0);
    }
}
```

Параметры, которые мы передаём в «системную функцию», определяют, с какими данными работает система. В этом случае, `greet_people` будет выполняться для всех объектов `Person` и `Name`.

Вы можете интерпретировать приведённый выше `Query` как: «перечисли каждый компонент `Name` для сущностей, которые также имеют компонент `Person`»:

Теперь мы просто регистрируем систему в нашем приложении:

```rust
fn main() {
    App::new()
        .add_startup_system(add_people)
        .add_system(hello_world)
        .add_system(greet_people)
        .run();
}
```

Запуская наше приложение мы увидим следующий результат:

```bash
hello world!
hello Elaina Proctor!
hello Renzo Hume!
hello Zayna Nieves!
```

Чудесно!

> Краткое примечание: "hello world!" может быть показана в другой последовательности, чем это делается выше. Это потому что системы запускаются параллельно по умолчанию
